﻿#include "globaltools.h"
#include <QApplication>
#include <QDesktopServices>
#include <QDir>
#include <QDomDocument>
#include <QStandardPaths>
#include <librtc.h>

QString cstring2QString(const char *str)
{
    return QString::fromUtf8(str);
}

QString string2QString(const std::string &str)
{
    if(str.empty())
        return QString();
    return QString::fromStdString(str);
}


QString string2QStringLocal(const std::string &str)
{
    return QString::fromLocal8Bit(str.c_str());
}

QByteArray QString2cstring(const QString& str)
{
    return str.toUtf8();
}

std::string QString2string(const QString &str)
{
    return str.toUtf8().constData();
}

static QString makePath(const QString& path)
{
    QDir dir(path);
    if(dir.exists() || dir.mkpath("."))
        return dir.absolutePath();
    return QString();
}

const QString appDataDir()
{
    static QString appDataPath = [](){
        QString result;
        QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
        if(!path.isEmpty())
            result = makePath(path);
        if(result.isEmpty())
            return QApplication::applicationDirPath();
        return result;
    }();
    return appDataPath;
}

const QString userProfileDir()
{
    static QString userProfPath = [](){
        QString result;
        QString path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
        if(!path.isEmpty())
            result = makePath(path+'/'+QApplication::applicationName());
        if(result.isEmpty())
            return QApplication::applicationDirPath();
        return result;
    }();
    return userProfPath;
}

const QString userDataDir(const QString &uid)
{
    if(uid.isEmpty())
        return userProfileDir();
    QString path = makePath(userProfileDir()+'/'+uid);
    if(path.isEmpty())
        return userProfileDir();
    return path;
}

void openUrl(const QUrl &url)
{
    QDesktopServices::openUrl(url);
}

const int virtualCameraId = 999;

const QString getCurrentVersion()
{
    static QString currentVer = [](){
        const QString component = QLatin1Literal("app.main");
        QString currentVer;
        QFile f(QApplication::applicationDirPath()+QLatin1Literal("/components.xml"));
        if(f.open(QIODevice::ReadOnly))
        {
            QDomDocument doc;
            bool ret = doc.setContent(&f);
            f.close();
            if(ret)
            {
                QDomElement root = doc.documentElement();
                if(component.isEmpty())
                    currentVer = root.firstChildElement("ApplicationVersion").text();
                else
                {
                    QDomElement package = root.firstChildElement("Package");
                    while(!package.isNull())
                    {
                        if(package.firstChildElement("Name").text() == component)
                        {
                            currentVer = package.firstChildElement("Version").text();
                            break;
                        }
                        package = package.nextSiblingElement("Package");
                    }
                }
            }
        }

        if(currentVer.isEmpty())
        {
#ifdef VER_PRODUCTVERSION_STR
            currentVer = VER_PRODUCTVERSION_STR;
            if(!currentVer.isEmpty())
            {
    #ifdef QT_DEBUG
            currentVer.append("-debug");
    #endif
            }
            else
#endif
    #ifdef QT_DEBUG
            currentVer = "debug";
    #else
            currentVer = "unknown";
    #endif
        }
        else
        {
    #ifdef QT_DEBUG
            currentVer.append("-debug");
    #endif
        }
        return currentVer;
    }();
    return currentVer;
}

#ifdef Q_OS_WIN
#include <qt_windows.h>
#include <QDir>
QString winGetLastError()
{
    LPVOID lpMsgBuf;
    DWORD dw = GetLastError();
    QString msg;

    if(0!=FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL ))
        msg = QString::fromWCharArray((LPCTSTR)lpMsgBuf);

    LocalFree(lpMsgBuf);
    return msg;
}

#include <DbgHelp.h>
static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
    QString path;
    if(qApp && !(path = QApplication::applicationFilePath()).isEmpty())
    {
        QFileInfo fi(path);
        QString strDumpFile = QDir::toNativeSeparators(userProfileDir()+'/'+fi.baseName()+"_"+QString(getCurrentVersion()).remove('.')+QDateTime::currentDateTime().toString("_yyyyMMddHHmmsszzz")+".dmp");

        SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };

        HANDLE fileHandle = CreateFile((const wchar_t*)strDumpFile.utf16(),
                                GENERIC_WRITE,
                                FILE_SHARE_READ | FILE_SHARE_WRITE,
                                &securityAtts,
                                CREATE_NEW,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);
        if(fileHandle == INVALID_HANDLE_VALUE && GetLastError()==ERROR_FILE_EXISTS)
            fileHandle = CreateFile((const wchar_t*)strDumpFile.utf16(),
                                    GENERIC_WRITE,
                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                                    &securityAtts,
                                    TRUNCATE_EXISTING,
                                    FILE_ATTRIBUTE_NORMAL,
                                    NULL);
        if(fileHandle != INVALID_HANDLE_VALUE)
        {
            MINIDUMP_EXCEPTION_INFORMATION ExInfo;

            ExInfo.ThreadId = ::GetCurrentThreadId();
            ExInfo.ExceptionPointers = ExceptionInfo;
            ExInfo.ClientPointers  = NULL;

            // write the dump
            BOOL bOK = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, MiniDumpNormal, &ExInfo, NULL, NULL);
            CloseHandle(fileHandle);
        }
    }

    return EXCEPTION_CONTINUE_SEARCH;
}
#endif

void runAfterApplication()
{
#if !defined(QT_DEBUG) && defined(Q_OS_WIN)
    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
#endif
}

QVariant getParam(const QVariantHash &container, int key)
{
    return container[QString::number(key)];
}

bool hasParam(const QVariantHash &container, int key)
{
    return container.contains(QString::number(key));
}

int removeParam(QVariantHash &container, int key)
{
    return container.remove(QString::number(key));
}

const QByteArray create_mid(uint curtime, const QString &msg)
{
    return create_mid(curtime, msg.toUtf8());
}

const QByteArray create_mid(uint curtime, const QByteArray &msg)
{
    //generate random string
    int size = 8 / 4 * 3;
    static bool srand_init = false;
    if (!srand_init)
    {
        srand(curtime);
        srand_init = true;
    }
    QByteArray raw(size,0);
    for (int i = 0; i < size; i++)
    {
        raw[i] = rand();
    }
    std::string str = raw.toBase64(QByteArray::Base64UrlEncoding|QByteArray::OmitTrailingEquals).constData();
    size = 6;
    raw.fill(0, size);
    uint n = qrand();
    raw[0] = n;
    raw[1] = curtime>>8;
    raw[2] = curtime;
    n = QApplication::applicationPid() + qHash(msg,curtime);
    raw[3] = n>>16;
    raw[4] = n>>8;
    raw[5] = n;

    QByteArray tmp = raw.toBase64(QByteArray::Base64UrlEncoding|QByteArray::OmitTrailingEquals);
    if(tmp.size()>8)
        tmp.resize(8);
    return tmp.append(str.c_str(),8).replace('-','I').replace('_','i');
}

#include <QHostAddress>

QString getHost(const QString &fullAddress)
{
    //地址为空
    if(fullAddress.isEmpty())
        return QString();
    QRegExp ipRx("(\\d+\\.\\d+\\.\\d+\\.\\d+)(:\\d+)?");
    //不匹配正则表达式
    if(!ipRx.exactMatch(fullAddress))
        return QString();
    QString host = ipRx.cap(1);
    QHostAddress address;
    //无法解析IP地址
    if(!address.setAddress(host))
        return QString();
    QString port = ipRx.cap(2);
    if(!port.isEmpty())
    {
        port = port.mid(1); //去除第一个冒号
        bool ok = false;
        port.toUShort(&ok);
        if(!ok)
        {
            //端口号解析失败
            return QString();
        }
    }
    //返回IP地址
    return host;
}
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl>
#include "httppost.h"
void getProxy(const QString &domain, QObject *receiver, const char *member)
{
    postJson(QUrl(domain+"/userApi/getSystemInfo"), QJsonDocument(QJsonObject({{"appname", QApplication::applicationName()}})).toJson(QJsonDocument::Compact), receiver, member);
}
